<?php

// Textile definition dataset -- First Draft, July 15, 2014
// (After I finally read the specification I doubted this would work. But 
// it turns out that the attribute parsing can be done by a single function.)

$gmlp_translate['STRIP'] = '';
$gmlp_translate['NEWLINE'] = "\n";

$gmlp_translate['EOL'] = array('<br>','<p>','</p>',"\n");
define('EOL_BR',0);
define('EOL_P1',1);
define('EOL_P2',2);
define('EOL_NL',3);

$gmlp_translate['entitytranslate'] = 0;

$gmlp_translate['skip'] = array(
);

$gmlp_translate['lines'] = array(
'/^h([1-6])\.\s*(.*)/' => '<h$1>$2</h$1>',
'/^fn([0-9]+)\.\s*(.*)/' => '<span id="fn$1"></span><sup>$1</sup>$2',
);

$gmlp_translate['line'] = array(
);

$gmlp_translate['inlines'] = array(
// from Parser.php
'/([0-9]+[\])]?[\'"]? ?)[xX]( ?[\[(]?)(?=[+-]?[0-9]*\.?[0-9]+)/' => '$1&#215;$2',
'/(\w|\))\'(\w)/' => '$1&#8217;$2',
'/(\s|\h|\v)\'(\d+\w?)\b(?![.]?[\w]*?\')/' => '$1&#8217;$2',
"/([([{])'(?=\S)/" => '$1&#8216;',
'/(\S)\'(?=(?:\s|\h|\v)|[[:punct:]]|<|$)/' => '$1&#8217;',
"/'/" => '&#8216;',
'/([([{])"(?=\S)/' => '$1&#8220;',
'/(\S)"(?=(?:\s|\h|\v)|[[:punct:]]|<|$)/' => '$1&#8221;',
'/"/' => '&#8220;',
'/\b([A-Z0-9]{2,})\b(?:[(]([^)]*)[)])/' => '<acronym title="$2">$1</acronym>',
'/([^.]?)\.{3}/' => '$1&#8230;',
'/--/' => '&#8212;',
'/ - /' => ' &#8211; ',
'/(\b ?|(?:\s|\h|\v)|^)[([]TM[])]/i' => '$1&#8482;',
'/(\b ?|(?:\s|\h|\v)|^)[([]R[])]/i' => '$1&#174;',
'/(\b ?|(?:\s|\h|\v)|^)[([]C[])]/i' => '$1&#169;',
'/[([]1\/4[])]/' => '&#188;',
'/[([]1\/2[])]/' => '&#189;',
'/[([]3\/4[])]/' => '&#190;',
'/a[([]o[])]/' => '&#176;',
'/[([]\+\/-[])]/' => '&#177;',

'/\b\[([0-9]+)\]/' => '<sup><a href="#fn$1">$1</a></sup>',
// need a little help for this one:
'/%(.+)%/U' => 'textile_span',

// the entities are from above
'/\[&#8220;(.*)&#8221;:(.*)\]/' => '<a href="$2">$1</a>',
'/&#8220;(.*)\s*\((.*)\)&#8221;:(http:\S*)/' => '<a href="$3" title="$2">$1</a>',
'/&#8220;(.*)&#8221;:(http:\S*)/' => '<a href="$2">$1</a>',

'/!((?:[(]+|[)]+|<>|<|>|\=|\^|-|~).*)!/' => 'textile_img',
'/!(.*)\((.*)\)!/' => '<img src="$1" alt="$2">',
'/!(.*)!:(\S*)/' => '<img src="$1">',

);

$gmlp_translate['chars'] = array(
'**' => 'b',
'__' => 'i',
'*' => 'strong',
'_' => 'em',
'??' => 'cite',
'@' => 'code',
'-' => 'del',
'+' => 'ins',
'^' => 'sup',
'~' => 'sub',
'_' => 'em',
);

$gmlp_translate['wordbeg'] = '/(^|[^a-zA-Z=;\/])';
$gmlp_translate['wordend'] = '([^a-zA-Z\/\]]|$)/U';


$gmlp_translate['blocks']['p'] = array(
'begin' => "/^p([(]*)([)]*)(<>|<|>|\=|\^|-|~|)(.*)\.\s+/",
'function' => 'textile_block',
);

// more here later...


$gmlp_translate['blocks']['ol'] = array(
'begin' => '/^#\s+/',
'function' => 'textile_olist',
);

$gmlp_translate['blocks']['ul'] = array(
'begin' => '/^\*\s+/',
'end' => '/^\s*$/',
'first' => 1,
'continue' => 1,
'function' => 'textile_ulist',
);

$gmlp_translate['blocks']['pre'] = array(
'begin' => '/^<pre>/',
'end' => '/^<\/pre>/',
'pre' => '<pre>',
'post' => '</pre>',
'newline' => 1,
'replace' => 'textile_prehtml',
);

$gmlp_translate['blocks']['notranslate'] = array(
'begin' => '/^==/',
'end' => '/^==/',
);

// %<attrib>span%

function textile_span($s) {
	$a = textile_attr($s,TRUE);
	return "<span$a>$s</span>";
}

// !<attrib>src!

function textile_img($s) {
	$a = textile_attr($s,TRUE);
	return "<img$a src=\"$s\">";
}

// p<attrib>. Text

function textile_block(&$data, &$s, $re) {

	$a = textile_attr($s);
	$end = '/^\s*$/';
	while (($_ = array_shift($data)) !== NULL) {
		if (preg_match($end,$_))
			break;
		$s .= "$_\n";
	}
	array_unshift($data,$_);
	$s = str_replace("\n",'<br>',trim($s));
	$s = "<p$a>$s</p>";
}

function textile_olist(&$data, &$s, $re) {

// demonstrate here one way to read a block of lines from the input array 
// directly by array shift:
	$list = '';
	$l = 1;
	$end = '/^\s*$/';
	$_ = $s;
	do {
		if (preg_match($end,$_))
			break;
		if (!preg_match('/^(#+)(.*)/',$_,$res))
			$li = '<br>';
		else {
			$_ = trim($res[2]);
			$t = strlen($res[1]);
			$li = '<li>';
			if ($t > $l)
				$li = '<ol><li>';
			if ($t < $l)
				$li = '</ol><li>';
			$l = $t;
		}
		gmlp_convert_str($_);
		$list .= "$li$_";
	} while (($_ = array_shift($data)) !== NULL);
	array_unshift($data,$_);

	$s = "<ol>$list</ol>";
}

function textile_ulist(&$data, &$s, $re) {

// demonstrate here other way to read a block of lines from the input array
// via support function that returns block as array from begin to end as 
// defined by the block data:
	$block = gmlp_read_block($data,$s,$re);
	$list = '';
	$l = 1;
	foreach ($block as $_) {
		if (!preg_match('/^(\*+)(.*)/',$_,$res))
			$li = '<br>';
		else {
			$_ = trim($res[2]);
			$t = strlen($res[1]);
			$li = '<li>';
			if ($t > $l)
				$li = '<ul><li>';
			if ($t < $l)
				$li = '</ul><li>';
			$l = $t;
		}
		gmlp_convert_str($_);
		$list .= "$li$_";
	}

	$s = "<ul>$list</ul>";
}

function textile_prehtml($s) {
	if ($s != '<code>' && $s != '</code>')
		return htmlentities($s);
	return $s;
}

// parse all combinations of attributes and return a CSS formated string

function textile_attr(&$s, $span = FALSE) {
static $qa = array(
'<>' => 'text-align:justify;',
'<' => 'text-align:left;',
'>' => 'text-align:right;',
'=' => 'text-align:center;',
'^' => 'vertical-align:top;',
'-' => 'vertical-align:middle;',
'~' => 'vertical-align:bottom;',
);
static $be = '(bq|p|bc|notextile|pre|h[1-6]|fn|)';
static $pd = '(\(*)(\)*)';
static $qe = '(<>|<|>|\=|\^|-|~|)';
static $ae = '([\(\{\[].*[\)\}\]])';

// see if combination includes class/id/lang attributes:
	$re = "/^$be$pd$qe$ae\.\s+(.*)/";
	if ($span)
		$re = "/^$be$pd$qe$ae(.*)/";
	if ($r = preg_match($re,$s,$res)) {
		list (,,$pl,$pr,$q,$attrs,$s) = $res;
	}
	else {
		if ($r === FALSE) {
			var_dump($re,$s);
			echo "<br>";
			return '';
		}
// re-try without class/id/lang attributes:
		$re = "/^$be$pd$qe\.\s+(.*)/";
		if ($span)
			$re = "/^$be$pd$qe(.*)/";
		if (!preg_match($re,$s,$res))
			return '';
		list (,,$pl,$pr,$q,$s) = $res;
	}

	$s = "$s\n";
	$cl = $id = $st = $la = '';

	if (isset($attrs) && $attrs) {
		// got class/id/style string and now parse them
		preg_match_all('/(\{.*\})|(\(.*\))|(\[.*\])/',$attrs,$res);
		foreach ($res[0] as $attr) {
			$type = ($attr) ? $attr[0] : '';
			$attr = substr($attr,1,-1);

			switch ($type) {
			case '(':
				if (($i = strpos($attr,'#')) === FALSE)
					$cl = $attr;
				if ($i === 0)
					$id = substr($attr,1);
				if ($i) {
					$t = explode('#',$attr);
					$cl = $t[0];
					$id = $t[1];
				}
				break;
			case '{':
				$st = $attr;
				if (substr($st,-1) != ';')
					$st .= ';';
				break;
			case '[':
				$la = $attr;
				break;
			}
		}
	}
	if ($pl)
		$st .= 'padding-left:'.strlen($pl).'em;';
	if ($pr)
		$st .= 'padding-right:'.strlen($pr).'em;';
	if ($q) $st .= $qa[$q];
	if ($cl) $cl = ' class="'.$cl.'"';
	if ($id) $id = ' id="'.$id.'"';
	if ($st) $st = ' style="'.$st.'"';
	if ($la) $la = ' lang="'.$la.'"';

	return $cl.$id.$st.$la;
}

return 1;
